LIBRARY ieee;
USE ieee.std_logic_1164.all;
use ieee.numeric_std.all;
LIBRARY altera;
use altera.altera_primitives_components.all;

-- 19:15 -> 22:30
-- 09:30 -> 11:00 (very little progress)
-- 14:00 -> 15:30

ENTITY DE0 IS
	PORT
	(
		-- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx --
		-- for prac 6 you will only use the following port signals
		-- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx --
		CLOCK_50 : IN STD_LOGIC; -- 50MHz in-circuit clock
		LEDG : OUT STD_LOGIC_VECTOR(9 DOWNTO 0); -- the 10 green LEDs on the DE0 board
		SW : IN std_LOGIC_VECTOR(9 DOWNTO 0); -- the 10 switches on the DE0 board
		BUTTON : IN STD_LOGIC_VECTOR(0 TO 2);  -- the 3 buttons on the DE0 board
		HEX0_D : INOUT STD_LOGIC_VECTOR(0 TO 6); -- the LEDs of the 7-segment display (right)
		HEX1_D : INOUT STD_LOGIC_VECTOR(0 TO 6); -- the LEDs of the 7-segment display
		HEX2_D : INOUT STD_LOGIC_VECTOR(0 TO 6); -- the LEDs of the 7-segment display
		HEX3_D : INOUT STD_LOGIC_VECTOR(0 TO 6); -- the LEDs of the 7-segment display (left)

		-- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx --
		-- ignore the rest of the PORT for prac 6  -- 
		-- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx --
		FL_BYTE_N : IN STD_LOGIC;
		FL_CE_N : IN STD_LOGIC;
		FL_OE_N : IN STD_LOGIC;
		FL_RST_N : IN STD_LOGIC;
		FL_RY : IN STD_LOGIC;
		FL_WE_N : IN STD_LOGIC;
		FL_WP_N : IN STD_LOGIC;
		FL_DQ15_AM1 : IN STD_LOGIC;
		PS2_KBCLK : IN STD_LOGIC;
		PS2_KBDAT : IN STD_LOGIC;
		PS2_MSCLK : IN STD_LOGIC;
		PS2_MSDAT : IN STD_LOGIC;
		UART_RXD : IN STD_LOGIC;
		UART_TXD : IN STD_LOGIC;
		UART_RTS : IN STD_LOGIC;
		UART_CTS : IN STD_LOGIC;
		SD_CLK : IN STD_LOGIC;
		SD_CMD : IN STD_LOGIC;
		SD_DAT0 : IN STD_LOGIC;
		SD_DAT3 : IN STD_LOGIC;
		SD_WP_N : IN STD_LOGIC;
		LCD_RW : IN STD_LOGIC;
		LCD_RS : IN STD_LOGIC;
		LCD_EN : IN STD_LOGIC;
		LCD_BLON : IN STD_LOGIC;
		VGA_HS : IN STD_LOGIC;
		VGA_VS : IN STD_LOGIC;
		HEX0_DP : IN STD_LOGIC;
		HEX1_DP : IN STD_LOGIC;
		HEX2_DP : INOUT STD_LOGIC;
		HEX3_DP : IN STD_LOGIC;
		DRAM_CAS_N : IN STD_LOGIC;
		DRAM_CS_N : IN STD_LOGIC;
		DRAM_CLK : IN STD_LOGIC;
		DRAM_CKE : IN STD_LOGIC;
		DRAM_BA_0 : IN STD_LOGIC;
		DRAM_BA_1 : IN STD_LOGIC;
		DRAM_LDQM : IN STD_LOGIC;
		DRAM_UDQM : IN STD_LOGIC;
		DRAM_RAS_N : IN STD_LOGIC;
		DRAM_WE_N : IN STD_LOGIC;
		CLOCK_50_2 : IN STD_LOGIC;
		FL_ADDR : IN STD_LOGIC_VECTOR(0 TO 21);
		FL_DQ : IN STD_LOGIC_VECTOR(0 TO 14);
		GPIO0_D : INOUT STD_LOGIC_VECTOR(0 TO 31);
		GPIO0_CLKIN : IN STD_LOGIC_VECTOR(0 TO 1);
		GPIO0_CLKOUT : IN STD_LOGIC_VECTOR(0 TO 1);
		GPIO1_CLKIN : IN STD_LOGIC_VECTOR(0 TO 1);
		GPIO1_CLKOUT : IN STD_LOGIC_VECTOR(0 TO 1);
		GPIO1_D : IN STD_LOGIC_VECTOR(0 TO 31);
		LCD_DATA : IN STD_LOGIC_VECTOR(0 TO 7);
		VGA_G : IN STD_LOGIC_VECTOR(0 TO 3);
		VGA_R : IN STD_LOGIC_VECTOR(0 TO 3);
		VGA_B : IN STD_LOGIC_VECTOR(0 TO 3);
		DRAM_DQ : IN STD_LOGIC_VECTOR(0 TO 15);
		DRAM_ADDR : IN STD_LOGIC_VECTOR(0 TO 12)
		);
END DE0;

ARCHITECTURE structure OF DE0 IS

-- Component definitions
component hex_display 
	port(	number			: in integer range 0 to 9;
			hex				: out std_logic_vector(6 downto 0);
			blink,blink_en	: in std_logic := '0');
end component;
component clk_divider is 
	port ( 	clk_count		: in integer range 0 to 50000000;
				clk_in			: in std_logic;
				clk_en			: in std_logic := '1';
				clk_out 			: inout std_logic := '0' );
end component;

signal start_stop, reset, ch_state
								: std_LOGIC;
signal sw_count 			: integer range 0 to 5999 := 0;
signal bt_count			: integer range 0 to 9999 := 0;
signal tm_count			: integer range 0 to 5999 := 0;

type state 					is (A, B, C, D);
signal current_state		: state := A;
signal next_state 		: state := A;
signal counting 			: std_logic := '0';

signal clk_rt				: std_logic := '0';
signal clk_rt_en			: std_logic := '0';
signal blink				: std_logic := '1';
signal hex_out_0, hex_out_1, hex_out_2, hex_out_3
								: integer range 0 to 9;
								
begin
	
	-- button definitions
	start_stop 	<= button(2);
	reset 		<= button(1);
	ch_state		<= button(0);
	
	-- display definitions
	blink <= '1' when current_state = A else '0';
	hex_disp_0	: hex_display port map (number => hex_out_0, hex => hex0_D, blink_en => blink, blink => clk_rt);
	hex_disp_1	: hex_display port map (number => hex_out_1, hex => hex1_D, blink_en => blink, blink => clk_rt);
	hex_disp_2	: hex_display port map (number => hex_out_2, hex => hex2_D, blink_en => blink, blink => clk_rt);
	hex_disp_3	: hex_display port map (number => hex_out_3, hex => hex3_D, blink_en => blink, blink => clk_rt);
	
	with current_state select
		hex_out_0 <=
			sw_count rem 10 when B,
			bt_count rem 10 when C,
			tm_count rem 10 when D,
			0 when others;
	with current_state select
		hex_out_1 <=
			(sw_count / 10) rem 10 when B,
			(bt_count / 10) rem 10 when C,
			(tm_count / 10) rem 10 when D,
			0 when others;
	with current_state select
		hex_out_2 <=
			(sw_count / 60) rem 10 when B,
			(bt_count / 100) rem 10 when C,
			(tm_count / 60) rem 10 when D,
			0 when others;
	with current_state select
		hex_out_3 <=
			(sw_count / 60 / 10) rem 10 when B,
			(bt_count / 100 / 10) rem 10 when C,
			(tm_count / 60 / 10) rem 10 when D,
			0 when others;
		

	-- debug led definitions
	ledg(0) <= counting;
	ledg(1) <= blink;
	ledg(2) <= clk_rt_en;
	ledg(3) <= clk_rt;
	
	-- state led definitions
	ledg(9) <= '1' when current_state = A else '0';
	ledg(8) <= '1' when current_state = B else '0';
	ledg(7) <= '1' when current_state = C else '0';
	ledg(6) <= '1' when current_state = D else '0';
	
	hex2_DP <= clk_rt when counting = '1' else '0';
	
	-- clock definitions
	clk_div_rt	: clk_divider port map (clk_count => 25000000, clk_in => CLOCK_50, clk_out => clk_rt, clk_en => clk_rt_en);
	clk_rt_en <= '1' when (current_state = A) or (current_state = B and counting = '1') or (current_state = D and start_stop = '0') else '0';
	
	-- main state machine
	-- sets next_state
	process (sw)
	begin
		case to_integer(unsigned(sw(1 downto 0))) is
			when 0 =>
				next_state <= A;
			when 1 =>
				next_state <= B;
			when 2 =>
				next_state <= C;
			when 3 =>
				next_state <= D;
			when others =>
		end case;
	end process;

	-- state progress only
	-- sets current_state
	process(next_state) 
	begin
		current_state <= next_state;
	end process;
	
	-- counting process
	-- sets counting 
	process(start_stop)
	begin
		if current_state = B then
			if falling_edge(start_stop) then
				counting <= not counting;
			end if;
		end if;
	end process;
	
	-- button process
	-- sets counts
	process (clk_rt, button)
	begin
		case current_state is 
			when B =>
				if reset = '0' then
					sw_count <= 0;
				elsif rising_edge(clk_rt) then
					if counting = '1' then
						if rising_edge(clk_rt) then
							sw_count <= sw_count + 1;
						end if;
					end if;
				end if;
			when C =>
				if reset = '0' then
					bt_count <= 0;
				elsif falling_edge(start_stop) then
					bt_count <= bt_count + 1;
				end if;
			when D =>
				if reset = '0' then
					tm_count <= 0;
				elsif rising_edge(clk_rt) then
					tm_count <= tm_count + 1;
				end if;
			when others =>
		end case;
	end process;
END structure;

